<template>
  <div class="goods-sku">
    <dl v-for="item in goods.specs" :key="item.name">
      <dt>{{ item.name }}</dt>
      <dd>
        <template v-for="item2 in item.values" :key="item2.name">
          <img
            @click="clickSpecs(item, item2)"
            v-if="item2.picture"
            :src="item2.picture"
            :title="item2.name"
            :alt="item2.name"
            :class="{ selected: item2.selected, disabled: item2.disabled }"
          />
          <span
            @click="clickSpecs(item, item2)"
            :class="{ selected: item2.selected, disabled: item2.disabled }"
            v-else
          >
            {{ item2.name }}
          </span>
        </template>
      </dd>
    </dl>
  </div>
</template>

<script>
// 导入幂集算法
import powerSet from '@/vender/power-set'
// 分隔符(用户自定义)
const star = '★'
// 🔔 根据skus数据得到路径字典对象
const getPathMap = (skus) => {
  const pathMap = {}
  // 0. 遍历后端返回 skus 集合
  skus.forEach(sku => {
    // 1. 过滤出有库存有效的sku
    if (sku.inventory) {
      // 2. 得到sku属性值数组 [a,b,c] 格式
      const specs = sku.specs.map(item => item.valueName)
      // 3. 通过 powerSet 幂集算法计算所有子集(用户操作时可能出现的所有情况)
      const powerSetRes = powerSet(specs)
      // console.log(powerSetRes)
      // 4. 设置给路径字典对象
      powerSetRes.forEach(item => {
        // 把结果转字符串方便使用
        const key = item.join(star)
        // console.log(111, key)
        // 如果 key 值还没有，初始化空数组
        if (!pathMap[key]) pathMap[key] = []
        // 往数组中添加 skuid
        pathMap[key].push(sku.id)
      })
    }
  })
  // 返回路径字典
  return pathMap
}

// 🔔 得到当前选中规格集合
const getSelectedArr = (specs) => {
  const arr = []
  specs.forEach(spec => {
    const obj = spec.values.find(item => item.selected)
    arr.push(obj ? obj.name : undefined)
  })
  return arr
}

// 更新按钮的禁用状态
const updateDisabledStatus = (specs, pathMap) => {
  // 每一行规格都要模拟一遍
  specs.forEach((spec, index) => {
    // 先获取当前选中的规格集合
    const curr = getSelectedArr(specs)
    // 🔔 根据当前选中，模拟用户的下一次选中
    // console.log(spec, curr)
    spec.values.forEach(val => {
      // 已经选中的按钮不用再模拟
      if (val.selected) return
      // 模拟其他未选中的值
      curr[index] = val.name
      // console.log('模拟后的结果', curr)
      // 过滤无效值得到key
      const key = curr.filter(v => v).join(star)
      // console.log('模拟后的结果', key)
      // 在字典中查找，设置禁用状态
      val.disabled = !pathMap[key]
    })
  })
}

// 根据 skuId 实现默认选中状态
const initSelectedStatus = (goods, skuId) => {
  // 根据当前 skuId 查找到 sku对象
  const skuObj = goods.skus.find(item => item.id === skuId)
  // console.log(111, skuObj)
  if (skuObj) {
    // 遍历更新 goods 对象的规格，实现视图的默认选中
    goods.specs.forEach((spec, index) => {
      // console.log(222, spec)
      // 从 sku 对象中，根据下标获取到规格名
      const name = skuObj.specs[index].valueName
      // 更新页面的规格选中状态
      spec.values.forEach(val => { val.selected = name === val.name })
    })
  }
}

export default {
  name: 'GoodsSku',
  emits: ['change'],
  props: {
    goods: {
      type: Object,
      default: () => ({}),
      required: true
    },
    // 🔔 这个是购物车列表中用于实现默认选中
    skuId: {
      type: String,
      default: ''
    }
  },
  setup (props, { emit }) {
    // 💥 注意：setup钩子只执行一次
    // console.log('setup钩子被执行了~~~')
    // 把 skus 组合处理成路径字典 (不在字典中的规格要在页面中禁用)
    const pathMap = getPathMap(props.goods.skus)
    // console.log('获取路径字典处理结果', pathMap)

    // 🔔 根据传入的skuId默认选中规格按钮
    initSelectedStatus(props.goods, props.skuId)

    // 🔔用户点击前，也要初始化按钮禁用状态的
    updateDisabledStatus(props.goods.specs, pathMap)
    // 点击规格高亮
    const clickSpecs = (parent, currItem) => {
      // console.log({ parent, currItem })
      // 如果是禁用状态不作为
      if (currItem.disabled) return
      // 如果当前是选中高亮
      if (currItem.selected) {
        // 取消高亮
        currItem.selected = false
      } else {
        // 排它思想：
        // 同级全部取消高亮
        parent.values.forEach(item => {
          item.selected = false
        })
        // 当前高亮
        currItem.selected = true

        // 高亮的同时，获取当前选中的规格
        const currSpec = getSelectedArr(props.goods.specs)
        // console.log('当前选中的规格是', currSpec)
        // 情况1：不完整的，传 空对象 (数组包含 undefined)
        if (currSpec.includes(undefined)) {
          emit('change', {})
        } else {
          // 情况2：完整规格，传 skuId 价格 原价 库存 规格文字
          const key = currSpec.join(star)
          // console.log(key)
          // 从字典中根据规格查找 skuId
          const [skuId] = pathMap[key]
          // console.log(skuId)
          const { price, oldPrice, inventory, specs } = props.goods.skus.find(item => item.id === skuId)
          // console.log({ price, oldPrice, inventory, specs })
          emit('change', {
            skuId,
            price,
            oldPrice,
            inventory,
            // 这个数据在购物车列表的时候需要用到
            attrsText: specs.map(item => `${item.name}:${item.valueName}`).join(' ')
          })
        }
      }

      // 🔔 用户点击后，更新按钮禁用状态的
      updateDisabledStatus(props.goods.specs, pathMap)
    }

    return { clickSpecs }
  }
}
</script>

<style scoped lang="less">
.sku-state-mixin () {
  border: 1px solid #e4e4e4;
  margin-right: 10px;
  cursor: pointer;
  &.selected {
    border-color: @xtxColor;
  }
  &.disabled {
    opacity: 0.6;
    border-style: dashed;
    cursor: not-allowed;
  }
}
.goods-sku {
  padding-left: 10px;
  padding-top: 20px;
  dl {
    display: flex;
    padding-bottom: 20px;
    align-items: center;
    dt {
      width: 50px;
      color: #999;
    }
    dd {
      flex: 1;
      color: #666;
      > img {
        width: 50px;
        height: 50px;
        .sku-state-mixin ();
      }
      > span {
        display: inline-block;
        height: 30px;
        line-height: 28px;
        padding: 0 20px;
        .sku-state-mixin ();
      }
    }
  }
}
</style>
